#  Proctor.py -- Proctor testing for ProctorTicket
#  Copyright (C) 2008 Zachary Voase <cracka80@gmail.com>
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
#  02110-1301, USA.

"""ProctorTicket.Proctor:
Library containing the Proctor testing component of the ProctorTicket
application. Contains abstractions for running and reading Proctor tests."""

from cStringIO import StringIO
from os import getcwdu, chdir
from popen2 import popen2
from proctorlib.result import ResultFactory, TestResult
import Utils
import proctorlib
import time

def StatusFilter( status=['ERROR', 'FAIL'] ):
    """StatusFilter(<iterable>):
Returns a filter function, which makes sure that results have one status from
the given options. This returns True/False. Used for generating result filters
for the Test class."""
    return lambda result: result.status.lower() in [ s.lower() for s in status ]

class Test( object ):
    """Test(<resultsFilter: StatusFilter(['ERROR', 'FAIL'])>):
An object which provides a few wrappings around the use of the Proctor testing
system. Test results can be found in the 'results' attribute, which is a list of
proctorlib.result.TestResult objects. Also includes a 'currentTime' attribute, a
datetime() of the time of instantiation of the object, and a 'rawData'
attribute, a file-like object which contains the actual parseable output from
'proctorbatch'."""
    
    rawData = StringIO()
    currentTime = time.strftime( "%s" )
    
    def __init__( self, resultsFilter=StatusFilter(), *args, **kwargs ):
        self.resultslist = Utils.FilteredList( filterFunction=resultsFilter )
        self.reader = ResultFactory( self.resultslist.append )
        self.resultsDict = {}
        object.__init__( self, *args, **kwargs )
    
    def loadFromLog( self, file_like_object ):
        """Test.from_file(<file-like object>):
Reads data from the file-like object, adds it to the rawData attribute, parses
it and adds results to resultList depending on resultsFilter method."""
        lines = file_like_object.readlines()
        self.rawData.writelines( lines )
        for line in lines: self.reader.feed( line )
        file_like_object.close()
        self.cleanResults( self.resultslist )
        self.resultslist = Utils.FilteredList( filterFunction=self.resultslist.filterFunction )
    
    def loadFromTest( self, directory=getcwdu() ):
        """Test.runTest(directory=<string: os.getcwdu()>):
Runs the 'proctorbatch' command line client and gets parseable output for the
proctorlib results parser. This output is then processed by loadFromLog in the
same way as usual."""
        Utils.pushd( unicode( directory ) )
        output, input = popen2( "proctorbatch -q --parsable" )
        data = StringIO( output.read() )
        output.close()
        input.close()
        Utils.popd()
        self.loadFromLog( data )
    
    def mergeResultsDict( self, dictin ):
        for key, value in dictin.items():
            if self.resultsDict.has_key( key ):
                if isinstance( value, list ):
                    self.resultsDict[key] += value
                else:
                    self.resultsDict[key].append( value )
            else:
                if isinstance( value, list ):
                    self.resultsDict[key] = value
                else:
                    self.resultsDict[key] = [ value ]
    
    def cleanResults( self, results ):
        """Test.cleanResults(<list>):
Goes through the list of TestResult objects, groups together all results from
the same test class into lists, removes duplicated entries and then uses 
'mergeResultsDict' method to place all test class result lists into
'resultsDict' attribute."""
        dictOut = {}
        uniqueResults = Utils.UniquifyResults( results )
        classNames = [ Utils.GetTestClass( res ) for res in uniqueResults ]
        for i in range( len( uniqueResults ) ):
            if dictOut.has_key( classNames[i] ):
                dictOut[classNames[i]].append( uniqueResults[i] )
            else:
                dictOut[classNames[i]] = [ uniqueResults[i] ]
        self.mergeResultsDict( dictOut )